package tcinert;
/*
 * Diplomova Prace: Vyuziti embedded modulu pro monitoring zivotnich funkci 
 *                  pacienta
 * Trida: Jadro.java
 * Autor: Tomas Cinert
 * Vytvoreno: 14.4.2012
 */

import com.siemens.icm.io.ATCommandListener;
import com.siemens.icm.io.CommConnectionControlLinesListener;
import java.util.Calendar;
import java.util.Date;
import java.util.TimerTask;
import javax.microedition.rms.RecordStoreException;
import com.siemens.icm.io.ATCommandFailedException;
import com.siemens.icm.io.CommConnectionControlLines;
import java.io.InputStream;
import java.io.IOException;
import javax.microedition.io.Connector;
import tcinert.Stav;
import java.util.Timer;

/**
 * Trida Jadro - hlavni program, ktery ma na starosti obsluhu behu(inicializace,
 * cteni dat, obsluha databaze, upload dat)
 * @author Tomas Cinert
 * @version 0.9.1
 */
public class Jadro implements Runnable, ATCommandListener{
    /* Aktualni cas pro log a pro zapis do DB*/
    Calendar datum;
    /* Seriova komunikace*/
    CommConnectionControlLines spojeni;
    CommConnectionControlLinesListener comListener;
    /* Programova cast */
    Inicializace init;
    Databaze databaze;
    Zaznam zaznam;
    /* Vlakna */
    Thread vlaknoHlavni=new Thread(this);
    Thread cteciVlakno=null;
    Thread uploadVlakno=null;
    Thread SPIvlakno=null;
    /* Pomocne promenne*/
    int c;
    private boolean loop=true;
    private boolean SPI=false;
    int i=0;
    private int pocetChyb=0;
    String[][] data=null;
    Stav reset;
    String a=null;
    StringBuffer buffer;
    final int uspani=100;
    Timer stopky;
    TimerTask pripojeni;
    
    /**
     *Konstruktor
     * - inicalizuje veskere tridy a spousti vlakna (cteni dat a upload)
     **/
    public Jadro(Stav reset,Zaznam zaznam) {
        this.zaznam=zaznam;
        this.reset=reset;
        buffer=new StringBuffer();
        stopky=new Timer();
        
        /* Program startuje */
        zaznam.zapis("Hlavni program startuje",typZapisu.Informativni);
        zaznam.zapis("Inicializace modemu",typZapisu.Informativni);
        /** Inicializace modemu */
        try {
            init=new Inicializace(reset,zaznam);
            init.setPin(1);         // Pokud inciializace probehne v pohode, tak muzem jet dal
            zaznam.zapis("Inicializace modemu OK",typZapisu.Informativni);
        } catch (IllegalStateException ex) {
            zaznam.zapis("Inicializace modemu"+ex.toString(),typZapisu.Chybovy);
            reset.setStav(true);
        } catch(ATCommandFailedException ex){
            zaznam.zapis("Inicializace modemu"+ex.toString(),typZapisu.Chybovy);
            reset.setStav(true);
        }catch (IOException ex){
            zaznam.zapis("1. Inicializace portu"+ex.toString(),typZapisu.Chybovy);
            try {
                init.inicializacePort(); // zkusit znovu zapnout, cist nejakej citac chyb a pokud ani podruhy se nepodari, tak vypnout a poslat sms, obe logovat
                init.setPin(1);         // Pokud inciializace v druhym kole probehne v pohode, tak muzem jet dal
            } catch (IOException ex2) {
                zaznam.zapis("2.Inicializace portu"+ex.toString(),typZapisu.Chybovy);
                init.poslaniSMS("Nepodarilo se nam otevrit GPIO z duvodu"+ex2.toString());
            }
        }
        init.at.addListener(this);
        /* Seriove spojeni */
        zkouskaSpojeni();
        /* Inicializace Databaze */
        zaznam.zapis("Inicializace databaze",typZapisu.Informativni);
        try {
            databaze=new Databaze();
            zaznam.zapis("Inicializace databaze probehla v poradku.",typZapisu.Informativni);
            zaznam.zapis("Databaze obsahuje"+databaze.pocetZaznamu()+"zaznamu",typZapisu.Informativni);
            if((data=databaze.odeslano())!=null)
            {
                zaznam.zapis("Databaze obsahuje neodeslane zaznamy.",typZapisu.Informativni);
                vlaknoUpload(false);
                if(data!=null){
                    zaznam.zapis("Pokud odeslat podruhe.",typZapisu.Informativni);
                    vlaknoUpload(false);
                    if(data!=null){
                        zaznam.zapis("Data ani na podruhe nebyly odeslany. Upload olozen.",typZapisu.Chybovy);
                    }
                    else{
                        zaznam.zapis("Data na podruhe odeslany.",typZapisu.Informativni);
                        databaze.nastaveniOdeslano();
                    }
                }
                else{
                    zaznam.zapis("Data odeslany.",typZapisu.Informativni);
                    databaze.nastaveniOdeslano();
                }
                    
                
            }
        } catch (RecordStoreException ex) {
            zaznam.zapis("Databaze nebyla otevrena z duvodu:"+ex.toString(),typZapisu.Chybovy);
        }catch (Exception ex){
            zaznam.zapis("Problem s inicialiazaci databaze"+ex.toString(),typZapisu.Chybovy);
        }
        
        
        
        
        
        
        
        
    }
    /**
     *Spousti vlakno
     **/
    public void start() {
        loop = true;
        zaznam.zapis("Hlavni program nabiha",typZapisu.Informativni);
        vlaknoHlavni.start();
    }
    
    /**
     *Metoda na zastaveni vlakna (pri zmacknuti tlacitka)
     **/
    public void stop() {
        loop = false;
        zaznam.zapis("Hlavni vlakno ukonceno",typZapisu.Informativni);
        try {
            vlaknoHlavni.join();
        } catch (InterruptedException ex) {
            ex.printStackTrace();
        }
    }
    /**
     *Metoda na otevreni serioveho spojeni
     * - synchronizovana
     **/
    private synchronized void serioveSpojeni() {
        zaznam.zapis("Inicializace serioveho spojeni",typZapisu.Informativni);
        uzavreniSpojeni();      // pokud uz existuje, uzavreme
        try {
            spojeni = (CommConnectionControlLines) Connector.open("comm:COM0;baudrate=4800", Connector.READ_WRITE, true);
            comListener=new CommConnectionControlLinesListener(){
                public void DTRChanged(boolean SignalState) {
                    if(SignalState){
                        init.ATsend("AT+CFUN=1,0\r");
                        vlaknoCteni(true);
                    } else {
                        init.ATsend("AT+CFUN=9,0\r");
                    }
                }
            };
            spojeni.addListener(comListener);
            zaznam.zapis("Otvirame seriove spojeni",typZapisu.Informativni);
        } catch (IOException ex) {
            zaznam.zapis("Nepodarilo se nam otevrit seriove spojeni",typZapisu.Chybovy);
        }
        
        
    }
    /**
     *Vytvori cteci vlakno
     **/
    private synchronized void vlaknoCteni(boolean prijemDat) {
        serioveSpojeni();
        if(cteciVlakno!=null){
            cteciVlakno=null;
        }
        cteciVlakno=new Thread(new Spojeni(zaznam, buffer,spojeni,reset));
        cteciVlakno.start();
        try {
            cteciVlakno.join();
        } catch (InterruptedException ex) {
            cteciVlakno.yield();
        }
        ulozeniDat(prijemDat);
    }
    /**
     *Metoda na uzavreni spojeni
     **/
    private void uzavreniSpojeni() {
        try {
            if(spojeni!=null){
                comListener=null;
                spojeni.close();
            }
        } catch (IOException ex) {
            zaznam.zapis("Problem s uzavrenim spojeni:"+ex.toString(),typZapisu.Chybovy);
        }
    }
    /**
     *Metoda na tvorbu vlakna pro odeslani dat do vzdalene DB, provede kontrolu odeslani a nastaveni statusu
     **/
    public synchronized void vlaknoUpload(boolean prubeh)
    {
        zaznam.zapis("Provadime upload dat.",typZapisu.Informativni);
        reset.setData(false);
        uzavreniSpojeni();
        if(uploadVlakno!=null)
        {
            uploadVlakno=null;           
        }
        if(init.testSignalu())
        {
            try{
                uploadVlakno=new Thread(new Pripojeni(zaznam,data,reset));
                uploadVlakno.start();
                uploadVlakno.join();
            }catch(Exception ex){
                zaznam.zapis("Upload se nepovedl z nasledujiciho duvodu."+ex.toString(),typZapisu.Chybovy);
            }
            
        }
        else
        {
            zaznam.zapis("Neni dostupny signal. Upload odlozen",typZapisu.Chybovy);
        }
        if(prubeh)
        {
            if(reset.getData()){
                databaze.nastaveniOdeslano();
                zaznam.zapis("Data odeslany.Opetovne uspani.",typZapisu.Informativni);
             //   init.ATsend("AT+CFUN=0,9\r");
            }
            else
            {
                zaznam.zapis("Data neodeslany.Opetovne uspani.",typZapisu.Chybovy);
              //  init.ATsend("AT+CFUN=0,9\r");
            }
        }
    }
    
    private synchronized void vlaknoSPI(String dataSPI)
    {
        if(SPIvlakno!=null)
        {
            SPIvlakno=null;           
        }
        try{
                SPIvlakno=new Thread(new SPI(zaznam,dataSPI,reset,buffer));
                SPIvlakno.start();
                SPIvlakno.join();
            }catch(Exception ex){
                zaznam.zapis("Prijeti dat se nepovedlo. "+ex.toString(),typZapisu.Chybovy);
            }
        ulozeniDat(reset.getData());
    }
    /**
     * Pokud selhalo spojeni s deskou
     **/
    private void chybaKomunikace() {
        init.poslaniSMS("Selhalo spojeni s deskou"); 
        zaznam.zapis("Pokus uzavrit seriove spojeni a otevreni SPI spojeni",typZapisu.Informativni);
        uzavreniSpojeni();
        otevreniSPI();      
    }
    
    
    
    /**
     *Metoda na inicializaci a otevreni SPI spojeni (alternativni komunikace)
     **/
    private void otevreniSPI() {
        init.otevritSPI();
        try {
            init.zmenaPinu(true);
        } catch (IOException ex) {
            ex.printStackTrace();
        }
    }  // Udelat listener na AT^SPI .. chybu reportovat, domyslet tu chybu tam
    
    private void ulozeniDat(boolean prijato){
        if(prijato)
        {
            reset.setStav(false);
            zaznam.zapis("Zapis dat do databaze.",typZapisu.Informativni);
            databaze.zapisDB(System.currentTimeMillis(),upravaDat(0,4),upravaDat(6,9),upravaDat(10,14),testPadu()); 
            init.ATsend("AT+CFUN=9,0\r");
        }
    }
    /**
     *Metoda na upravu dat prijatych
     **/
    public double upravaDat(int zacatek, int konec)
   {
       char[] pole = null;
       buffer.getChars(zacatek,konec,pole,0);
       return(Double.parseDouble((new String(pole))));
   }
    /**
     *Test na pad v datech
     **/
    public boolean testPadu()
    {
        if((buffer.charAt(16))=='A')
        {
            return true;
        }
        else
        {
            return false;
        }
    }
    /**
     *Hlavni smycka
     * - cekame na prijem dat
     * - jednou za hodinu upload dat
     **/
    public void run() {
        zaznam.zapis("Hlavni program nabiha", typZapisu.Informativni);
        init.ATsend("AT^SBV\r");
        zaznam.zapis("Napeti baterie je: "+init.getNapeti()+" mV",typZapisu.Informativni);
        zaznam.zapis("Uspavame zarizeni. Cekame na data",typZapisu.Informativni);
        //init.nastaveniCasu("02/02/02,02:02:02");
        stopky.scheduleAtFixedRate(new casVlakno(),10000,10000);
        init.ATsend("AT+CFUN=9,0\r");
          
            
            
            
            
            
    }      
    private void zkouskaSpojeni(){
        vlaknoCteni(false);
        if(!reset.getData()) {
            zaznam.zapis("Nemame data. Spoustime cteni znova",typZapisu.Chybovy);
            init.reset();
            vlaknoCteni(false);
            if(!reset.getData()) {
                zaznam.zapis("Podruhe nebyly prijata data. Prepiname na komunikace po SPI",typZapisu.Chybovy);
                chybaKomunikace();
            }
            
        } else {
            zaznam.zapis("Inicializace serioveho spojeni v poradku",typZapisu.Informativni);
            reset.setStav(false);
            try {
                init.setPin(3);
                init.setPin(2);
            } catch (IOException ex) {
                ex.printStackTrace();
            }
        }
    }        
        
    /**
     *Vnorena trida je podtridou TimerTask - slouzi ke spousteni uploadu kazdou hodinu
     * - navic zkousi seriovou komunikaci (pri problemech)
     */
    private class casVlakno extends TimerTask{
        public void run() {
            zaznam.zapis("Spoustime naplanovany upoload.",typZapisu.Informativni);
           vlaknoUpload(true);
           if(SPI)
           {
               SPI=false;
               init.reset();
               zkouskaSpojeni();
               
           }
           zaznam.zapis("Napeti baterie je :"+init.getNapeti()+" mV",typZapisu.Informativni);
           init.ATsend("AT+CFUN=9,0\r");
        }
        
    }
    /* Implementovane metody ATCommandListener */
    /**
     *Metoda na zachyceni URC - dodelat na OTAP
     */
    public void ATEvent(String Event) {     // C
        if(Event.equalsIgnoreCase("^SPI:")){
            init.ATsend("AT+CFUN=1,0\r");
            vlaknoSPI(Event);
        }
    }

    public void RINGChanged(boolean SignalState) {
    }

    public void DCDChanged(boolean SignalState) {
    }

    public void DSRChanged(boolean SignalState) {
    }

    public void CONNChanged(boolean SignalState) {
    }
}

